<?php

namespace app\api\controller;

use app\model\Mch;
use app\model\Order;
use app\model\Channel;
use think\Validate;
use think\Db;
class Pay extends Base
{
    
    /**
     * Undocumented 下单16500
     *
     * @return void
     */
    public function index(){
       
        //接收数据
        $data = $this->request->param();
        //数据验证
        $validate = $this->get_validate($data);
        //验证失败，返回失败信息
        if(!empty($validate)) return $this->jsonReturn($validate);
        //验证ip
        if($this->mch_ip($data['mch_id']) === false) return $this->jsonReturn('未绑定白名单');
        //获取商户基本信息
        $mch = Mch::get_mch($data['mch_id']);
        //判断商户号是否存在
        if(!$mch) return $this->jsonReturn("商户不存在");
        //判断商户状态
        if($mch->status == 2) return $this->jsonReturn("商户已锁定");
        //判断商户入金
        if($mch->rukuan == 2) return $this->jsonReturn("商户已禁止入金");
        //验证签名
        if($data['sign'] != get_sign($data,$mch->md5key)) return $this->jsonReturn("签名错误");
        //判断重复提交
       
        $info = Order::mch_order(['mch_id'=>$data['mch_id'],'out_trade_no'=>$data['out_trade_no']],'id');
        if($info) return $this->jsonReturn("订单重复提交");
        //查询商户渠道
        $channel = Mch::mch_channel($data['mch_id'],$data['service_type']);
        if(empty($channel)) return $this->jsonReturn("商户没开通支该付方式");        
        //遍历渠道，查找合适的
        $result = $this->choose_hannel($channel,abs($data['amount']/100));
        if(!is_array($result)) return $this->jsonReturn($result);
        //创建订单
        $order = Order::orderAdd($data,$result);
        if(!is_array($order)) return $this->jsonReturn($order);
        $response = array(
            "out_trade_no" => $order['out_trade_no'],
            "systen_no" =>$order['system_sn'],
            "link_url"=>APP_URL.'/pay/transit?parameter='.$order['system_sn']
        );
        return $this->jsonReturn($response);
    }
    /**
     * Undocumented 支付中转
     *
     * @return void
     */
    public function transit(){
        //接收订单号
        $systen_no = $this->request->param('parameter');
        //订单是否存在
        if(empty($systen_no)) return $this->jsonReturn("订单号不存在");
        //查询订单信息
        $info = Order::mch_order(['systen_no'=>$systen_no],'id,pay_status,channel_id,payment_id,systen_no,amount,return_url');
        //判断订单是否存在
        if(!$info) return $this->jsonReturn("订单不存在");
        //判断订单是否重置支付
        if($info->pay_status == 2) return $this->jsonReturn("重复支付");
        //订单重复
        if($info->pay_status == 3) return $this->jsonReturn("订单已关闭");
        //获取渠道编码
        $channel = Channel::get_channel($info->channel_id);
        //判断渠道是否存在
        if(empty($channel)) return $this->jsonReturn("获取渠道失败");
        //获取支付编码
        $payment = Channel::get_payment($info->payment_id);
        //判断支付类型是否存在
        if(empty($payment)) return $this->jsonReturn("获取支付类型失败");
        //调用渠道方法
        $adapterClass = "\channel\\{$channel['code']}";
        $data = [
            "systen_no" => $info->systen_no,//订单号
            "total_amount" => $info->amount,//下单金额
            "callback_url" => APP_URL.'/pay/notify/'.$channel['code'],//异步回调(不懂的不要去改动)
            "return_url" => $info->return_url //同步跳转
        ];
        //请求上游对接控制器
        $adapterClass::create_order($data,$payment['pay_type']);
    }
    /**
     * Undocumented 异步回调
     *
     * @return void
     */
    public function notify(){
        //接收所有数据
        $data = $this->request->param();
        get_log($data,$data['n_code']);
        if(!$data){
            return $this->jsonReturn('数据不存在');
        }
        //根据渠道类名获取渠道ip
        $white_ip = Channel::where('code',$data['n_code'])->value('white_ip');
        if(!$white_ip) $this->jsonReturn('渠道部不存在');
        //验证ip
        if(!in_array(get_client_ip(),explode("|",$white_ip))) $this->jsonReturn('不在指定的ip白名单内');
        
        $adapterClass = "\channel\\{$data['n_code']}";
        //删除渠道编码
        unset($data['n_code']);
        //异步回调处理
        $adapterClass::create_notify($data);
    }
    /**
     * Undocumented 同步跳转
     *
     * @return void
     */
    public function callback(){

        exit('支付完成');
    }
    /**
     * Undocumented 订单状态查询(自己生成的扫码页面)
     *
     * @return void
     */
    public function order_query(){
        $systen_no = $this->request->param("system_no",'','strip_tags,trim');

        $info = Order::where("systen_no",$systen_no)->field("pay_status,callback_url")->find();

        if($info && $info->pay_status == 2){

            return $this->jsonReturn(['url'=>$info->callback_url]);
        }
        return $this->jsonReturn('failure');
    }
    /**
     * Undocumented 验证IP
     *
     * @param [type] $mch
     * @return void
     */
    protected function mch_ip($mch){

        $info = Db::name("mch_white_ip")->where("mch_id",$mch)->find();
        if(empty($info)){
            return false;
        }
        if(!in_array(get_client_ip(),explode("|",$info['white_ip']))){
            return false;
        }
        return true;
    }
    /**
     * Undocumented 选择合适的支付类型
     *
     * @param [type] $data
     * @return void
     */
    protected function choose_hannel($data,$amount){
       
        //拆分
        $payment = explode("|",$data['payment']);
       
        //判断是否需要轮询
        if(count($payment) == 1){
            $arr = explode(":",$payment[0]);
            //获取支付类型信息
            $p = Channel::get_payment($arr[0]);
          
            if(empty($p)){
                return '不存在的支付类型';
            }
            if($p['status'] == 2){
                return '渠道已维护';
            }
            //判断金额最小
            if(intval($p['min_amount']) && $p['min_amount'] > $amount){
                return '最低金额'.$p['min_amount'].'元';
            }
            //判断金额最大
            if(intval($p['max_amount']) && $p['max_amount'] < $amount){
                return '最大金额'.$p['max_amount'].'元';
            }
            //倍数金额
            if(intval($p['double_amount'])){
                if(intval($amount) % $p['double_amount']){
                    return '提交金额必须是'.$p['double_amount'].'的倍数';
                }
            }
            //判断当日限额
            $actual_amount = Order::where("create_time",'between',[date('Y-m-d 00:00:00',time()),date('Y-m-d H:i:s',time())])->where("payment_id",$p['id'])->where("pay_status",2)->sum('actual_amount');
            if(!empty($p['qualified']) && $p['qualified'] < $actual_amount){
                return '当天额度已满';
            }
            //排除尾数金额(金额必须是整数,不能带小数点)
            if($p['exclude_tail']){
                //判断是否是整数
                if(intval($amount) != $amount){
                    return '提交金额必须是整数';
                }
                $tails_arr = explode("|", $p['exclude_tail']);
                if(!empty($tails_arr)){
                    $tails = intval($amount) % 10;
                    if(in_array($tails, $tails_arr)){
                        
                        return '金额尾数不能带有'.implode(',',$tails_arr).'其中一个';
                    }
                }  
            }
            //固定金额
            if($p['fixed_amount']){
                $peroid_arr = explode("|", $p['fixed_amount']);
                $flag = false;
                foreach($peroid_arr as $v){
                    if($v == $amount){
                        $flag = true;
                        break;
                    }
                }
                if(!$flag){
                    return '只能提交'.implode(',',$peroid_arr).'的金额';
                }
            }
            //并发控制
            if(!empty($arr[3])){
                $r = redis_concurrent($p['pay_type'].'_'.$arr[0],$arr[3]);
                if($r){
                    return $r;
                }
            }
            return ['patment_id'=>$arr[0],'run_rate'=>$arr[1]];
        }else{//轮询
            $pay = array();
            $t = array();
            $i = 0;
            foreach ($payment as $value) {
                $arr = explode(":",$value);
                //获取支付类型数据
                $p = Channel::get_payment($arr[0]);
                //渠道部存在
                if(empty($p)){
                    continue;
                }
                //渠道已维护
                if($p['status'] == 2){
                    continue;
                }
                //判断当日限额
                $actual_amount = Order::where("create_time",'between',[date('Y-m-d 00:00:00',time()),date('Y-m-d H:i:s',time())])->where("payment_id",$p['id'])->where("pay_status",2)->sum('actual_amount');
                if(!empty($p['qualified']) && $p['qualified'] < $actual_amount){
                    continue;
                }
                //判断金额最小
                if($p['min_amount'] && $p['min_amount'] > $amount){
                    continue;
                }
                //判断金额最大
                if($p['max_amount'] && $p['max_amount'] < $amount){
                    continue;
                }
                //固定金额
                if($p['fixed_amount']){
                    $peroid_arr = explode("|", $p['fixed_amount']);
                    $flag = false;
                    foreach($peroid_arr as $v){
                        if($v == $amount){
                            $flag = true;
                            break;
                        }
                    }
                    if(!$flag){
                        continue;
                    }
                }
                //倍数金额
                if($p['double_amount']){
                    if(intval($amount) % $p['double_amount']){
                        continue;
                    }
                }
                //排除尾数金额(金额必须是整数,不能带小数点)
                if($p['exclude_tail']){
                    //判断是否是整数
                    if(intval($amount) != $amount){
                        continue; 
                    }
                    $tails_arr = explode("|", $p['exclude_tail']);
                    if(!$tails_arr || empty($tails_arr)){
                        continue;
                    }
                    $tails = intval($amount) % 10;
                    if(in_array($tails, $tails_arr)){
                        continue;
                    }
                }
                //权重
                for($j=0; $j<$arr[2]; $j++){
                    $i++;
                    $pay[$arr[0]][] = $i;
                }
                $t[] = $arr;
                //并发控制
                if(!empty($arr[3])){
                    $r = redis_concurrent($p['pay_type'].'_'.$arr[0],$arr[3]);
                    if($r){
                        continue;
                    }
                }
            }//遍历结束
            if(empty($i)){
                return '没有合适的渠道';
            }
            $payment_id = 0;
            //随机选择一条渠道
            $rand = mt_rand(1,$i);
            foreach($pay as $k=>$v){
                if(in_array($rand, $v)){
                    $payment_id = $k;
                    break;
                }
            }
            $t = array_filter($t, function($item) use ($payment_id) { return $item[0] == $payment_id; });
            $t =array_pop($t);
            return ['patment_id'=>$t[0],'run_rate'=>$t[1]];
        }
    }
    /**
     * Undocumented 验证字段
     *
     * @param [type] $data
     * @return void
     */
    protected function get_validate($data){
        $rule = [
            'mch_id'=>'require',
            'out_trade_no'=>'require|length:10,20',
            'amount'=>'require|number',
            'service_type'=>'require|in:wxwap,wx,aliwap,aliqr,flash,qqwap,qq,unionpay,quick',
            'callback_url'=>'require|url',
            'return_url'=>'require|url',
            'sign'=>'require'
        ];
        $msg = [
            'mch_id.require'=>'商户号不能为空',
            'out_trade_no.require'=>'订单号不能为空',
            'out_trade_no.length'=>'订单号长度在10到20位之间',
            'amount.require'=>'金额不能为空',
            'amount.number'=>'金额必须是整数',
            'service_type.require'=>'支付类型不能为空',
            'service_type.in'=>'支付类型错误',
            'callback_url.require'=>'异步回调地址不能为空',
            'callback_url.url'=>'异步回调格式错误',
            'return_url.require'=>'同步地址不能为空',
            'return_url.url'=>'同步地址格式错误',
            'sign.require'=>'签名不能为空'
        ];
        $validate = new Validate($rule, $msg);
        if (!$validate->check($data)){
        	$message = $validate->getError();
        	return $message;
        }
        return false;
    }









}